package ace.tool.generate.code.impl.resolver.scheme.resolver.core;

import ace.tool.generate.code.impl.manager.common.EntityModelManager;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.ApiProject;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.CoreProject;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.SdkProject;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.AggregateClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.AggregateImplClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.ApiImplClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.CoreAutoConfigClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.CoreBootstrapScannerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.CoreConstantClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.EntityClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.GraphqlAdminControllerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.InitListenerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.InitServiceClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.InitServiceImplClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.ManagerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.ManagerImplClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.PropertiesClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.RepositoryClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.RepositoryScannerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.RestAdminControllerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.RestRpcControllerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.RestTenantAdminControllerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.resources.GraphqlDtoFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.resources.GraphqlInputFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.resources.GraphqlSchemaAutoGenerateFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.resources.GraphqlSchemaFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.resources.LiquibaseInitTableFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.resources.LiquibaseTableFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestApiTestClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestBaseTestClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestBoostrapMainApplicationClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestGraphqlAdminControllerTestClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestGraphqlTestFileBundle;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestMainSuiteClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestResourceApplicationYmlFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestRestAdminControllerTestClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.test.TestStartupTestClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.AutoConfigurationImportsInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.SpringFactoriesInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.ClassFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.CommonInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.ProjectInfo;
import ace.tool.generate.code.impl.resolver.scheme.resolver.ClassFileInfoResolver;
import ace.tool.generate.code.impl.resolver.scheme.resolver.ProjectInfoResolver;
import ace.tool.generate.code.impl.resolver.scheme.resolver.common.AutoConfigurationImportsInfoResolver;
import ace.tool.generate.code.impl.resolver.scheme.resolver.common.SpringFactoriesInfoResolver;
import ace.tool.generate.code.impl.service.model.input.GenerateInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelInput;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;

/**
 * @author caspar
 * @date 2023/11/17 10:34
 */
@RequiredArgsConstructor
public class CoreProjectResolver {

  private final GenerateInput input;
  private final ProjectInfo moduleProjectInfo;
  private final CommonInfo commonInfo;
  private final ApiProject apiProject;
  private final SdkProject sdkProject;
  private final EntityModelManager entityModelManager = new EntityModelManager();

  public CoreProject resolve() {
    ProjectInfo coreProjectInfo = this.getProjectInfo();

    CoreAutoConfigClassInfo coreAutoConfigClassInfo = this.getCoreAutoConfigClassInfo(coreProjectInfo);
    List<EntityClassInfo> entityClassInfos = this.getEntityClassInfos(coreProjectInfo);
    LiquibaseInitTableFileInfo liquibaseInitTableFileInfo = this.getLiquibaseInitTableFileInfo(coreProjectInfo);
    List<LiquibaseTableFileInfo> liquibaseTableFileInfos = this.getLiquibaseTableFileInfos(coreProjectInfo, entityClassInfos);
    CoreConstantClassInfo coreConstantClassInfo = this.getCoreConstantClassInfo(coreProjectInfo);
    List<RepositoryClassInfo> repositoryClassInfos = this.getRepositoryClassInfos(coreProjectInfo, entityClassInfos, coreConstantClassInfo);
    List<AggregateClassInfo> aggregateClassInfos = this.getAggregateClassInfos(coreProjectInfo, entityClassInfos);
    List<AggregateImplClassInfo> aggregateImplClassInfos = this.getAggregateImplClassInfos(coreProjectInfo, entityClassInfos);
    RepositoryScannerClassInfo repositoryScannerClassInfo = this.getRepositoryScannerClassInfo(coreProjectInfo);
    PropertiesClassInfo propertiesClassInfo = this.getPropertiesClassInfo(coreProjectInfo);
    List<ManagerClassInfo> managerClassInfos = this.getManagerClassInfos(coreProjectInfo, entityClassInfos);
    List<ManagerImplClassInfo> managerImplClassInfos = this.getManagerImplClassInfos(coreProjectInfo, entityClassInfos);
    List<RestTenantAdminControllerClassInfo> restTenantAdminControllerClassInfos = this.getRestTenantAdminControllerClassInfos(coreProjectInfo, entityClassInfos);
    InitListenerClassInfo initListenerClassInfo = this.getInitListenerClassInfo(coreProjectInfo);
    InitServiceClassInfo initServiceClassInfo = this.getInitServiceClassInfo(coreProjectInfo);
    InitServiceImplClassInfo initServiceImplClassInfo = this.getInitServiceImplClassInfo(coreProjectInfo);
    List<GraphqlAdminControllerClassInfo> graphqlAdminControllerClassInfos = this.getGraphqlAdminControllerClassInfos(coreProjectInfo, entityClassInfos);
    List<RestAdminControllerClassInfo> restAdminControllerClassInfos = this.getRestAdminControllerClassInfos(coreProjectInfo, entityClassInfos);
    List<RestRpcControllerClassInfo> restRpcControllerClassInfos = this.getRestRpcControllerClassInfos(coreProjectInfo, entityClassInfos);

    GraphqlSchemaFileInfo graphqlSchemaFileInfo = this.getGraphqlSchemaFileInfo(coreProjectInfo);
    List<GraphqlDtoFileInfo> graphqlDtoFileInfos = this.getGraphqlDtoFileInfos(coreProjectInfo, entityClassInfos);
    List<GraphqlInputFileInfo> graphqlInputFileInfos = this.getGraphqlInputFileInfos(coreProjectInfo, entityClassInfos);
    GraphqlSchemaAutoGenerateFileInfo graphqlSchemaAutoGenerateFileInfo = this.getGraphqlSchemaAutoGenerateFileInfo(
        coreProjectInfo, entityClassInfos, graphqlDtoFileInfos, graphqlInputFileInfos);

    TestMainSuiteClassInfo testMainSuiteClassInfo = this.getTestMainSuiteClassInfo(coreProjectInfo);
    TestBoostrapMainApplicationClassInfo testBoostrapMainApplicationClassInfo = this.getTestBoostrapMainApplicationClassInfo(coreProjectInfo);
    TestResourceApplicationYmlFileInfo testResourceApplicationYmlFileInfo = this.getTestResourceApplicationYmlFileInfo(coreProjectInfo);
    TestBaseTestClassInfo testBaseTestClassInfo = this.getTestBaseTestClassInfo(coreProjectInfo);
    List<TestApiTestClassInfo> testApiTestClassInfos = this.getTestApiTestClassInfos(coreProjectInfo, entityClassInfos);
    TestStartupTestClassInfo testStartupTestClassInfo = this.getTestStartupTestClassInfo(coreProjectInfo);
    List<TestGraphqlTestFileBundle> testGraphqlTestFileBundles =
        this.getTestGraphqlTestFileBundles(
            coreProjectInfo,
            entityClassInfos,
            graphqlDtoFileInfos,
            graphqlInputFileInfos,
            graphqlAdminControllerClassInfos);
    List<TestGraphqlAdminControllerTestClassInfo> testGraphqlAdminControllerTestClassInfos =
        this.getTestGraphqlAdminControllerTestClassInfos(coreProjectInfo, entityClassInfos);
    List<TestRestAdminControllerTestClassInfo> testRestAdminControllerTestClassInfos =
        this.getTestRestAdminControllerTestClassInfos(coreProjectInfo, entityClassInfos);

    List<ApiImplClassInfo> apiImplClassInfos = this.getApiImplClassInfos(input, coreProjectInfo, entityClassInfos, commonInfo, apiProject, managerClassInfos);

    return CoreProject.builder()
        .info(coreProjectInfo)
        .coreAutoConfigClassInfo(coreAutoConfigClassInfo)
        .springFactoriesInfo(this.getSpringFactoriesFileInfo(coreProjectInfo, coreAutoConfigClassInfo))
        .autoConfigurationImportsInfo(this.getAutoConfigurationImportsFileInfo(coreProjectInfo, coreAutoConfigClassInfo))
        .coreBootstrapScannerClassInfo(this.getCoreBoostrapScannerClassInfo(coreProjectInfo))
        .propertiesClassInfo(propertiesClassInfo)
        .entityClassInfos(entityClassInfos)
        .coreConstantClassInfo(coreConstantClassInfo)
        .repositoryClassInfos(repositoryClassInfos)
        .aggregateClassInfos(aggregateClassInfos)
        .aggregateImplClassInfos(aggregateImplClassInfos)
        .repositoryScannerClassInfo(repositoryScannerClassInfo)
        .restTenantAdminControllerClassInfos(restTenantAdminControllerClassInfos)
        .managerClassInfos(managerClassInfos)
        .managerImplClassInfos(managerImplClassInfos)
        .apiImplClassInfos(apiImplClassInfos)
        .initListenerClassInfo(initListenerClassInfo)
        .initServiceClassInfo(initServiceClassInfo)
        .initServiceImplClassInfo(initServiceImplClassInfo)
        .graphqlAdminControllerClassInfos(graphqlAdminControllerClassInfos)
        .restAdminControllerClassInfos(restAdminControllerClassInfos)
        .restRpcControllerClassInfos(restRpcControllerClassInfos)
        .graphqlSchemaFileInfo(graphqlSchemaFileInfo)
        .graphqlDtoFileInfos(graphqlDtoFileInfos)
        .graphqlInputFileInfos(graphqlInputFileInfos)
        .graphqlSchemaAutoGenerateFileInfo(graphqlSchemaAutoGenerateFileInfo)
        .liquibaseInitTableFileInfo(liquibaseInitTableFileInfo)
        .liquibaseTableFileInfos(liquibaseTableFileInfos)
        .testMainSuiteClassInfo(testMainSuiteClassInfo)
        .testBoostrapMainApplicationClassInfo(testBoostrapMainApplicationClassInfo)
        .testResourceApplicationYmlFileInfo(testResourceApplicationYmlFileInfo)
        .testBaseTestClassInfo(testBaseTestClassInfo)
        .testApiTestClassInfos(testApiTestClassInfos)
        .testStartupTestClassInfo(testStartupTestClassInfo)
        .testGraphqlTestFileBundles(testGraphqlTestFileBundles)
        .testGraphqlAdminControllerTestClassInfos(testGraphqlAdminControllerTestClassInfos)
        .testRestAdminControllerTestClassInfos(testRestAdminControllerTestClassInfos)
        .build();
  }

  private List<ApiImplClassInfo> getApiImplClassInfos(GenerateInput generateInput,
      ProjectInfo coreProjectInfo,
      List<EntityClassInfo> entityClassInfos,
      CommonInfo commonInfo,
      ApiProject apiProject,
      List<ManagerClassInfo> managerClassInfos) {
    return entityClassInfos.stream()
        .map(entityClassInfo -> {
          return new ApiImplClassInfoResolver(
              generateInput,
              entityClassInfo,
              coreProjectInfo,
              commonInfo,
              apiProject,
              managerClassInfos
          ).resolve();
        })
        .collect(Collectors.toList());
  }


  private CoreConstantClassInfo getCoreConstantClassInfo(ProjectInfo coreProjectInfo) {
    return CoreConstantClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  private List<TestRestAdminControllerTestClassInfo> getTestRestAdminControllerTestClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                this.getTestRestAdminControllerTestClassInfo(coreProjectInfo, entityClassInfo))
        .collect(Collectors.toList());
  }

  private TestRestAdminControllerTestClassInfo getTestRestAdminControllerTestClassInfo(
      ProjectInfo coreProjectInfo, EntityClassInfo entityClassInfo) {

    return TestRestAdminControllerTestClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .entityClassInfo(entityClassInfo)
        .build()
        .resolve();
  }

  private List<TestGraphqlAdminControllerTestClassInfo> getTestGraphqlAdminControllerTestClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                this.getTestGraphqlAdminControllerTestClassInfo(coreProjectInfo, entityClassInfo))
        .collect(Collectors.toList());
  }

  private TestGraphqlAdminControllerTestClassInfo getTestGraphqlAdminControllerTestClassInfo(
      ProjectInfo coreProjectInfo, EntityClassInfo entityClassInfo) {

    return TestGraphqlAdminControllerTestClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .entityClassInfo(entityClassInfo)
        .build()
        .resolve();
  }

  private List<TestGraphqlTestFileBundle> getTestGraphqlTestFileBundles(
      ProjectInfo coreProjectInfo,
      List<EntityClassInfo> entityClassInfos,
      List<GraphqlDtoFileInfo> graphqlDtoFileInfos,
      List<GraphqlInputFileInfo> graphqlInputFileInfos,
      List<GraphqlAdminControllerClassInfo> graphqlAdminControllerClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                this.getTestGraphqlTestFileBundle(
                    coreProjectInfo,
                    entityClassInfo,
                    graphqlDtoFileInfos,
                    graphqlInputFileInfos,
                    graphqlAdminControllerClassInfos))
        .collect(Collectors.toList());
  }

  private TestGraphqlTestFileBundle getTestGraphqlTestFileBundle(
      ProjectInfo coreProjectInfo,
      EntityClassInfo entityClassInfo,
      List<GraphqlDtoFileInfo> graphqlDtoFileInfos,
      List<GraphqlInputFileInfo> graphqlInputFileInfos,
      List<GraphqlAdminControllerClassInfo> graphqlAdminControllerClassInfos) {
    GraphqlDtoFileInfo graphqlDtoFileInfo =
        this.entityModelManager.getGraphqlDtoFileInfo(
            graphqlDtoFileInfos, entityClassInfo.getEntityModelId());
    GraphqlInputFileInfo graphqlInputFileInfo =
        this.entityModelManager.getGraphqlInputFileInfo(
            graphqlInputFileInfos, entityClassInfo.getEntityModelId());
    GraphqlAdminControllerClassInfo graphqlAdminControllerClassInfo =
        this.entityModelManager.getGraphqlAdminControllerClassInfo(
            graphqlAdminControllerClassInfos, entityClassInfo.getEntityModelId());
    return TestGraphqlTestFileBundleResolver.builder()
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .entityClassInfo(entityClassInfo)
        .commonInfo(commonInfo)
        .graphqlDtoFileInfo(graphqlDtoFileInfo)
        .graphqlInputFileInfo(graphqlInputFileInfo)
        .graphqlAdminControllerClassInfo(graphqlAdminControllerClassInfo)
        .build()
        .resolve();
  }

  private TestStartupTestClassInfo getTestStartupTestClassInfo(ProjectInfo coreProjectInfo) {
    return TestStartupTestClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  private List<TestApiTestClassInfo> getTestApiTestClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                TestApiTestClassInfoResolver.builder()
                    .coreProjectInfo(coreProjectInfo)
                    .entityClassInfo(entityClassInfo)
                    .commonInfo(commonInfo)
                    .input(input)
                    .build()
                    .resolve())
        .collect(Collectors.toList());
  }

  private TestBaseTestClassInfo getTestBaseTestClassInfo(ProjectInfo coreProjectInfo) {
    return TestBaseTestClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  private TestResourceApplicationYmlFileInfo getTestResourceApplicationYmlFileInfo(
      ProjectInfo coreProjectInfo) {
    return TestResourceApplicationYmlFileInfoResolver.builder()
        .coreProjectInfo(coreProjectInfo)
        .build()
        .resolve();
  }

  private TestBoostrapMainApplicationClassInfo getTestBoostrapMainApplicationClassInfo(
      ProjectInfo coreProjectInfo) {
    return TestBoostrapMainApplicationClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .coreProjectInfo(coreProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  private TestMainSuiteClassInfo getTestMainSuiteClassInfo(ProjectInfo coreProjectInfo) {
    ClassFileInfo classFileInfo =
        ClassFileInfoResolver.builder()
            .className("MainSuiteTest")
            .classNameSuffix("")
            .classPackagePrefix(input.getTestRootPackagePrefix())
            .rootPackageFullName(commonInfo.getRootPackageFullName())
            .sourceCodeRootDir(coreProjectInfo.getTestSourceCodeRootDir())
            .build()
            .resolve();
    return TestMainSuiteClassInfo.builder().info(classFileInfo).build();
  }

  private RepositoryScannerClassInfo getRepositoryScannerClassInfo(ProjectInfo coreProjectInfo) {
    ClassFileInfo classFileInfo =
        ClassFileInfoResolver.builder()
            .className("RepositoryScanner")
            .classNameSuffix("")
            .classPackagePrefix(input.getRepositoryScannerClassPackagePrefix())
            .rootPackageFullName(commonInfo.getRootPackageFullName())
            .sourceCodeRootDir(coreProjectInfo.getSourceCodeRootDir())
            .build()
            .resolve();

    return RepositoryScannerClassInfo.builder().info(classFileInfo).build();
  }

  private LiquibaseInitTableFileInfo getLiquibaseInitTableFileInfo(ProjectInfo coreProjectInfo) {
    return new LiquibaseInitTableFileInfoResolver(input, coreProjectInfo).resolve();
  }

  private List<LiquibaseTableFileInfo> getLiquibaseTableFileInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return input.getModels().stream()
        .map(
            modelInput -> {
              String entityModelId = entityModelManager.getEntityModelId(input, modelInput);
              EntityClassInfo entityClassInfo =
                  entityModelManager.getEntityClassInfoByEntityModelId(
                      entityClassInfos, entityModelId);
              return new LiquibaseTableFileInfoResolver(
                  input, modelInput, coreProjectInfo, entityClassInfo)
                  .resolve();
            })
        .collect(Collectors.toList());
  }

  private GraphqlSchemaAutoGenerateFileInfo getGraphqlSchemaAutoGenerateFileInfo(
      ProjectInfo coreProjectInfo,
      List<EntityClassInfo> entityClassInfos,
      List<GraphqlDtoFileInfo> graphqlDtoFileInfos,
      List<GraphqlInputFileInfo> graphqlInputFileInfos) {
    return new GraphqlSchemaAutoGenerateFileInfoResolver(
        input, entityClassInfos, graphqlDtoFileInfos, graphqlInputFileInfos, coreProjectInfo)
        .resolve();
  }

  private List<GraphqlInputFileInfo> getGraphqlInputFileInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new GraphqlInputFileInfoResolver(input, entityClassInfo, coreProjectInfo).resolve())
        .collect(Collectors.toList());
  }

  private List<GraphqlDtoFileInfo> getGraphqlDtoFileInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new GraphqlDtoFileInfoResolver(input, entityClassInfo, coreProjectInfo).resolve())
        .collect(Collectors.toList());
  }

  private GraphqlSchemaFileInfo getGraphqlSchemaFileInfo(ProjectInfo coreProjectInfo) {
    String fileFullName =
        String.format(
            "%s%s/%s",
            coreProjectInfo.getResourcesRootDir(),
            input.getGraphqlSchemaRootDirPrefix(),
            input.getGraphqlSchemaFileName());
    return GraphqlSchemaFileInfo.builder()
        .fileName(input.getGraphqlSchemaFileName())
        .fileFullName(fileFullName)
        .build();
  }

  private List<RestRpcControllerClassInfo> getRestRpcControllerClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new RestRpcControllerClassInfoResolver(
                    input, entityClassInfo, coreProjectInfo, commonInfo)
                    .resolve())
        .collect(Collectors.toList());
  }

  private List<RestAdminControllerClassInfo> getRestAdminControllerClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new RestAdminControllerClassInfoResolver(
                    input, entityClassInfo, coreProjectInfo, commonInfo)
                    .resolve())
        .collect(Collectors.toList());
  }

  private InitServiceImplClassInfo getInitServiceImplClassInfo(ProjectInfo coreProjectInfo) {
    ClassFileInfo classFileInfo =
        ClassFileInfoResolver.builder()
            .className(commonInfo.getProjectClassName())
            .classNameSuffix(input.getInitServiceImplClassNameSuffix())
            .classPackagePrefix(input.getInitServiceImplClassPackagePrefix())
            .rootPackageFullName(commonInfo.getRootPackageFullName())
            .sourceCodeRootDir(coreProjectInfo.getSourceCodeRootDir())
            .build()
            .resolve();

    return InitServiceImplClassInfo.builder().info(classFileInfo).build();
  }

  private InitServiceClassInfo getInitServiceClassInfo(ProjectInfo coreProjectInfo) {
    ClassFileInfo classFileInfo =
        ClassFileInfoResolver.builder()
            .className(commonInfo.getProjectClassName())
            .classNameSuffix(input.getInitServiceClassNameSuffix())
            .classPackagePrefix(input.getInitServiceClassPackagePrefix())
            .rootPackageFullName(commonInfo.getRootPackageFullName())
            .sourceCodeRootDir(coreProjectInfo.getSourceCodeRootDir())
            .build()
            .resolve();

    return InitServiceClassInfo.builder().info(classFileInfo).build();
  }

  private InitListenerClassInfo getInitListenerClassInfo(ProjectInfo coreProjectInfo) {
    ClassFileInfo classFileInfo =
        ClassFileInfoResolver.builder()
            .className(commonInfo.getProjectClassName())
            .classNameSuffix(input.getInitListenerClassNameSuffix())
            .classPackagePrefix(input.getInitListenerClassPackagePrefix())
            .rootPackageFullName(commonInfo.getRootPackageFullName())
            .sourceCodeRootDir(coreProjectInfo.getSourceCodeRootDir())
            .build()
            .resolve();

    return InitListenerClassInfo.builder().info(classFileInfo).build();
  }

  private List<RestTenantAdminControllerClassInfo> getRestTenantAdminControllerClassInfos(ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {

    return this.input.getModels()
        .stream()
        .map(modelInput -> new RestTenantAdminControllerClassInfoResolver(input,
            modelInput,
            entityClassInfos,
            coreProjectInfo,
            commonInfo)
            .resolve()
        )
        .flatMap(List::stream)
        .collect(Collectors.toList());
  }

  private List<ManagerImplClassInfo> getManagerImplClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {

    return this.input.getModels()
        .stream()
        .map(modelInput -> new ManagerImplClassInfoResolver(input, modelInput, entityClassInfos, coreProjectInfo, commonInfo)
            .resolve())
        .collect(Collectors.toList());

  }

  private List<ManagerClassInfo> getManagerClassInfos(ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return this.input.getModels()
        .stream()
        .map(modelInput -> new ManagerClassInfoResolver(input, modelInput, entityClassInfos, coreProjectInfo, commonInfo)
            .resolve())
        .collect(Collectors.toList());
  }

  private PropertiesClassInfo getPropertiesClassInfo(ProjectInfo coreProjectInfo) {
    return new PropertiesClassInfoResolver(input, coreProjectInfo, commonInfo).resolve();
  }

  private List<AggregateImplClassInfo> getAggregateImplClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new AggregateImplClassInfoResolver(
                    input, entityClassInfo, coreProjectInfo, commonInfo)
                    .resolve())
        .collect(Collectors.toList());
  }

  private List<AggregateClassInfo> getAggregateClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new AggregateClassInfoResolver(input, entityClassInfo, coreProjectInfo, commonInfo)
                    .resolve())
        .collect(Collectors.toList());
  }

  private List<RepositoryClassInfo> getRepositoryClassInfos(
      ProjectInfo coreProjectInfo,
      List<EntityClassInfo> entityClassInfos,
      CoreConstantClassInfo coreConstantClassInfo) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new RepositoryClassInfoResolver(
                    input, entityClassInfo, coreProjectInfo, commonInfo, coreConstantClassInfo)
                    .resolve())
        .collect(Collectors.toList());
  }

  private List<GraphqlAdminControllerClassInfo> getGraphqlAdminControllerClassInfos(
      ProjectInfo coreProjectInfo, List<EntityClassInfo> entityClassInfos) {
    return entityClassInfos.stream()
        .map(
            entityClassInfo ->
                new GraphqlAdminControllerClassInfoResolver(
                    input, entityClassInfo, coreProjectInfo, commonInfo)
                    .resolve())
        .collect(Collectors.toList());
  }

  private List<EntityClassInfo> getEntityClassInfos(ProjectInfo coreProjectInfo) {
    return input.getModels().stream()
        .map(p -> this.getEntityClassInfo(coreProjectInfo, p))
        .collect(Collectors.toList());
  }

  private EntityClassInfo getEntityClassInfo(
      ProjectInfo coreProjectInfo, GenerateModelInput modelInput) {
    return new EntityClassInfoResolver(
        input, modelInput, coreProjectInfo, commonInfo, apiProject, sdkProject
    )
        .resolve();
  }

  private CoreBootstrapScannerClassInfo getCoreBoostrapScannerClassInfo(
      ProjectInfo coreProjectInfo) {
    ClassFileInfo classFileInfo =
        ClassFileInfoResolver.builder()
            .className(commonInfo.getProjectClassName())
            .classNameSuffix(input.getCoreBootstrapScannerClassNameSuffix())
            .classPackagePrefix(input.getCoreBootstrapScannerClassPackagePrefix())
            .rootPackageFullName(commonInfo.getRootPackageFullName())
            .sourceCodeRootDir(coreProjectInfo.getSourceCodeRootDir())
            .build()
            .resolve();

    return CoreBootstrapScannerClassInfo.builder().info(classFileInfo).build();
  }

  private CoreAutoConfigClassInfo getCoreAutoConfigClassInfo(ProjectInfo coreProjectInfo) {
    return CoreAutoConfigClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .input(input)
        .coreProjectInfo(coreProjectInfo)
        .build()
        .resolve();
  }

  public SpringFactoriesInfo getSpringFactoriesFileInfo(
      ProjectInfo coreProjectInfo, CoreAutoConfigClassInfo coreAutoConfigClassInfo) {
    return SpringFactoriesInfoResolver.builder()
        .projectRootDir(coreProjectInfo.getRootDir())
        .classFullNameImports(Arrays.asList(coreAutoConfigClassInfo.getInfo().getClassFullName()))
        .build()
        .resolve();
  }

  public AutoConfigurationImportsInfo getAutoConfigurationImportsFileInfo(
      ProjectInfo sdkProjectInfo, CoreAutoConfigClassInfo coreAutoConfigClassInfo) {
    return AutoConfigurationImportsInfoResolver.builder()
        .projectRootDir(sdkProjectInfo.getRootDir())
        .classFullNameImports(Arrays.asList(coreAutoConfigClassInfo.getInfo().getClassFullName()))
        .build()
        .resolve();
  }

  public ProjectInfo getProjectInfo() {
    return ProjectInfoResolver.builder()
        .projectRootDir(moduleProjectInfo.getRootDir())
        .projectNamePrefix(input.getProjectNamePrefix())
        .projectName(input.getProjectName())
        .projectDisplayName(input.getProjectDisplayName())
        .projectNameSuffix(input.getCoreProjectNameSuffix())
        .build()
        .resolve();
  }
}
